#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <iostream>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <math.h>
#include "Camera.h"
#include <valarray>

Camera::Camera( )
{
	//double eyex, eyey, eyez; //eye location
	//double atx, aty, atz; // pointing eye towards
	//double initx, inity, initz; // where we started, if we need to reset
	//double refupx, refupy, refupz; // reference "up" direction for gluLookAt
	eyex = 0.0; eyey = 0.0; eyez = 5.0;
	initx = eyex;	inity = eyey;	initz = eyez;
	refupx = 0.0; refupy = 1.0; refupz = 0.0;
	atx = 0.0; aty = 0.0; atz = 0.0;
	znear = 1.0; zfar = 1000.0;
	fovdeg = 60.0; // fielf of view in degrees in x-direction
	this->bIsAttached = false; // am I attached to an object now?
	windowID = 1;
}

Camera::~Camera()
{

}

void Camera::Initialize( double ex, double ey, double ez,
				 double xat, double yat, double zat,
				 double minz, double maxz, double fovx )
{
	eyex = ex;	eyey = ey;	eyez = ez;
	atx = xat;	aty = yat;	atz = zat;
	refupx = 0.0; refupy = 1.0; refupz = 0.0;
	znear = minz;	zfar = maxz;
	fovdeg = fovx; // fielf of view in degrees in x-direction
	bIsAttached = false;

}

void Camera::Initialize(double ex, double ey, double ez, double minz, double maxz, double fovx)
{
	eyex = ex;	eyey = ey;	eyez = ez;
	atx = 0.0;	aty = 0.0;	atz = 0.0;
	initx = ex;	inity = ey;	initz = ez;
	refupx = 0.0; refupy = 1.0; refupz = 0.0;
	znear = minz;	zfar = maxz;
	fovdeg = fovx; // field of view in degrees
	bIsAttached = false;
}


Camera::Camera(double ex, double ey, double ez, double minz, double maxz, double fovx)
{
	Initialize( ex,  ey,  ez,  minz,  maxz, fovx);
}

void Camera::ResetPosition( )
{
	eyex = this->initx;
	eyey = this->inity;
	eyez = this->initz;
	atx = 0.0;
	aty = 0.0;
	atz = 0.0;
	if( this->bIsAttached )
		this->Detach();
	ResizeCallbackHandler( this->iWindowW, this->iWindowH );
}
void Camera::UpdateAttachedCamera()
{
	if( this->bIsAttached )	{
		this->ResizeCallbackHandler(this->iWindowW, this->iWindowH);
	}
	else;
		this->ResizeCallbackHandler(this->iWindowW, this->iWindowH);
}

void Camera::TranslateTo( double x, double y, double z )
{
	eyex = x; eyey = y;	eyez = z;
	ResizeCallbackHandler( this->iWindowW, this->iWindowH );
}

void Camera::TranslateBy( double dx, double dy, double dz)
{
	this->eyex += dx;	this->eyey += dy;	this->eyez += dz;
	this->ResizeCallbackHandler(iWindowW,iWindowH);
}

void Camera::PointAt( double x, double y, double z )
{
	atx = x;	aty = y;	atz = z;
	ResizeCallbackHandler( this->iWindowW, this->iWindowH );
}

void Camera::ResizeCallbackHandler(int w, int h)
{
	if( w == -1 ) {
		w = iWindowW;
		h = iWindowH;
	}

	int checkID = glutGetWindow(); // should equal this->windowID
	if( checkID != windowID ) {
		int* roo;
		delete roo;
	}
	// should already be set!
	//glutSetWindow( this->windowID );
	iWindowW = w;
	iWindowH = h;
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glViewport(0, 0, (GLsizei) w, (GLsizei) h);
	gluPerspective(fovdeg, (GLfloat) w / (GLfloat) h, znear, zfar);
	//The matrix maps the reference	point to the negative z	axis
	//  and the eye point to the origin.	
	
	// switch to model view
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(eyex, eyey, eyez, atx, aty, atz, refupx, refupy, refupz );

	
	
}

void Camera::ModelView()
{
	ResizeCallbackHandler(-1,-1);
}

void Camera::GetWH( int* w, int* h )
{
	*w = iWindowW;
	*h = iWindowH;
}